from flask import request, jsonify, session
from aps import app
from aps.models.item import *
from aps.models.fase import *
from aps.models.relacion import *
from aps.views.historial import *
from aps.models.grafo import *
from aps.models.proyectofase import *
from aps.models.itematributovalor import *

@app.route('/crear_relacion', methods=['GET', 'POST'])  
def crear_relacion():
    """
    Permite crear relaciones entre dos items.
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    idorigen  = request.form['origen']
    iddestino = request.form['destino']
    tipo      = request.form['tipo']
    
    item_origen  = bdsession.query(Item).filter_by(id=idorigen).first()
    item_destino = bdsession.query(Item).filter_by(id=iddestino).first()
    
    # Construimos un grafo del proyecto para detectar ciclos
    id_proyecto = bdsession.query(ProyectoFase).filter_by(idfase=item_origen.idfase).first().idproyecto
    g = Grafo(id_proyecto)
    paths = g.buscar_caminos(item_origen.id,item_destino.id)
    if len(paths) != 0:
        # Existen ciclos
        return jsonify ({'success':False,'message':'No se puede crear la relacion, produce ciclos.'})
    
    # Copiamos los atributos del item a una nueva version
    atributos = bdsession.query(ItemAtributoValor).filter_by(iditem=item_destino.id,version=item_destino.version).all()
    for atributo in atributos:
        tmp = ItemAtributoValor(atributo.iditem,atributo.idatributo,atributo.version+1,atributo.valor)
        bdsession.add(tmp)
    
    # Copiamos las relaciones del item a una nueva version
    relaciones = item_destino.get_relaciones()
    for relacion in relaciones:
        tmp2 = Relacion(relacion.idorigen,relacion.iddestino,relacion.vorigen,relacion.vdestino+1,relacion.tipo,relacion.estado)
        bdsession.add(tmp2)
    
    # Creamos la relacion en cuestion y la agregamos a la BD
    model = Relacion(idorigen,iddestino,item_origen.version,item_destino.version+1,tipo,'VALIDO')
    bdsession.add(model)
    
    # Actualizamos la version del item
    item_destino.version = item_destino.version + 1
    bdsession.merge(item_destino)
    
    # Creamos una entrada en el historial
    if tipo == 'PH':
        log_it(iddestino,session['usuario'],'el item ha establecido que el item cuyo id es ' + str(idorigen) + ', es su <b>PADRE</b>.')
        log_it(idorigen,session['usuario'],'se ha establecido que el item cuyo id es ' + str(iddestino) + ', es su <b>HIJO</b>.')
    else:
        log_it(iddestino,session['usuario'],'el item ha establecido que el item cuyo id es ' + str(idorigen) + ', es su <b>ANTECESOR</b>.')
        log_it(idorigen,session['usuario'],'se ha establecido que el item cuyo id es ' + str(iddestino) + ', es su <b>SUCESOR</b>.')
    
    return jsonify ({'success':True})

@app.route('/eliminar_relacion', methods=['GET', 'POST'])  
def eliminar_relacion():
    """
    Permite eliminar relaciones entre dos items.
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    idorigen  = request.form['origen']
    iddestino = request.form['destino']
    tipo      = request.form['tipo']
       
    origen  = bdsession.query(Item).filter_by(id=idorigen).first()
    destino = bdsession.query(Item).filter_by(id=iddestino).first()
    
    # Eliminamos la relacion de la BD
    relacion = bdsession.query(Relacion).filter_by(idorigen=origen.id,vorigen=origen.version,iddestino=destino.id,vdestino=destino.version).first()
    bdsession.delete(relacion)
    
    # Creamos una entrada en el historial
    log_it(iddestino,session['usuario'],'el item ha eliminado su relacion ' + tipo + ' con el item cuyo id es ' + str(idorigen))
    return jsonify ({'success':True})

@app.route('/consulta_relacion_x_item', methods=['GET', 'POST'])  
def consulta_relacion_x_item():
    """
    Permite obtener las relaciones de un item con otros.
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    id_item = request.args['iditem']
    # Obtenemos el item del cual queremos eliminar relaciones
    item = bdsession.query(Item).filter_by(id=id_item).first()
    # Obtenemos las relaciones y creamos un solo conjunto de relaciones
    relaciones = []
    for x in item.get_antecesores('ALL')['validas']:
        relaciones.append(x)
    for x in item.get_sucesores('ALL')['validas']:
        relaciones.append(x)
    # Procesamos los datos a enviar
    data = []
    
    for relacion in relaciones:
        item = {}
        item['idorigen'] = relacion.idorigen
        item['nombreorigen'] = bdsession.query(Item).filter_by(id=relacion.idorigen).first().nombre
        item['versionorigen'] = relacion.vorigen
        item['iddestino'] = relacion.iddestino
        item['nombredestino'] = bdsession.query(Item).filter_by(id=relacion.iddestino).first().nombre
        item['versiondestino'] = relacion.vdestino
        if relacion.tipo == u'PH':
            item['tipo'] = 'PADRE-HIJO'
        else:
            item['tipo'] = 'ANTECESOR-SUCESOR'
        data.append(item)
    return jsonify ({'success':True, 'data':data, 'total':len(data)})

@app.route('/resolver_relaciones', methods=['GET', 'POST'])  
def resolver_relaciones():
    """
    Permite resolver las relaciones de un item cuando este es revertido.
    @param request: objeto que encapsula la peticion del cliente
    @return: True si la accion se realizo correctamente
    """
    id_item = request.form['iditem']
    version = request.form['version']
    opcion  = request.form['opcion']
    
    # Obtenemos el item desde la BD
    item   = bdsession.query(Item).filter_by(id=id_item).first()
    # Obtenemos las relaciones actuales
    rels_a = item.get_relaciones(item.version-1)
    # Obtenemos las relaciones en la version en la cual se revirtio
    rels_b = item.get_relaciones(int(version))
    
    # Proceso de resolucion
    opcion = int(opcion)
    rels   = None
    if opcion == 1:
        # Mantemos las relaciones actuales
        rels = rels_a
    elif opcion == 2:
        # Utilizar las relaciones anteriores
        rels = rels_b
    elif opcion == 3:
        # Mezclar las relaciones
        def is_in(L,e):
            for l in L:
                if e.iddestino == l.iddestino and e.idorigen == l.idorigen:
                    return True
            return False
        
        rels = []
        tmp  = rels_a + rels_b
        for r in tmp:
            if not is_in(rels,r):
                rels.append(r)
    else:
        # Eliminar todas las relaciones
        rels = []
    
    # Construimos un grafo del proyecto para detectar ciclos
    id_proyecto = bdsession.query(ProyectoFase).filter_by(idfase=item.idfase).first().idproyecto
    g = Grafo(id_proyecto)
    
    # Agregamos las relaciones a la BD
    for r in rels:
        # Controlamos que la relacion no produzca ciclos
        paths = g.buscar_caminos(r.iddestino,r.idorigen)
        if len(paths) == 0:
            # No hay ciclos
            model = None
            if int(r.iddestino) == int(id_item):
                model = Relacion(r.idorigen,r.iddestino,r.vorigen,item.version,r.tipo,r.estado)
            else:
                model = Relacion(r.idorigen,r.iddestino,item.version,r.vdestino,r.tipo,r.estado)            
            # La relacion se agrega a la BD
            bdsession.add(model)
            # Actualizamos el grafo
            g.nodos[r.iddestino]['p'].append(r.idorigen)
            g.nodos[r.idorigen]['s'].append(r.iddestino)
    
    return jsonify ({'success':True})
